/*
 License
 
 Copyright © 2012 Kevin Kimmich
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights to 
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so, 
 subject to the following conditions:
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "crcore.h"
#include "xmlutils.h"

#ifdef ENABLE_LIBXML

void print_node(xmlNodePtr node)
{
	xmlNodePtr attributes = (xmlNodePtr)node->properties;
	
	printf("<%s ",node->name);
	
	while (attributes)
	{
		if (attributes->name)
		{
			printf("%s='%s' ",attributes->name,	XML_GET_CONTENT(attributes->children));
		}
		attributes = attributes->next;
	}
	printf(">");
}


xmlNodePtr copy_node(xmlNodePtr node)
{
	xmlNodePtr nnode = xmlNewNode(NULL,node->name);
	xmlNodePtr attributes = (xmlNodePtr)node->properties;
	
	while (attributes)
	{
		if (attributes->name)
		{
			xmlNewProp(nnode,attributes->name,	XML_GET_CONTENT(attributes->children));
		}
		attributes = attributes->next;
	}
	nnode->_private = node->_private;
	return nnode;
}

xmlNodePtr recursive_copy_node(xmlNodePtr node)
{
	xmlNodePtr newnode = xmlCopyNode(node,1);
	newnode->_private = node->_private;
	return newnode;
}

xmlChar *get_attribute_value(xmlNodePtr node, const char* attr_name)
{
	xmlNodePtr attributes = (xmlNodePtr)node->properties;
	
	while (attributes)
	{
		if (attributes->name && (strcmp((char*)attributes->name, attr_name)==0))
		{
			return XML_GET_CONTENT(attributes->children);
		}
		attributes = attributes->next;
	}
	return NULL;
}

xmlChar *get_attribute_value_copy(xmlNodePtr node, const char* attr_name)
{
	xmlNodePtr attributes = (xmlNodePtr)node->properties;
	
	while (attributes)
	{
		if (attributes->name && (strcmp((char*)attributes->name, attr_name)==0))
		{
			return xmlXPathCastNodeToString((xmlNodePtr)attributes);
		}
		attributes = attributes->next;
	}
	return NULL;
}


xmlNodePtr get_attribute_node(xmlNodePtr node, const char* attr_name) 
{
	xmlNodePtr attributes = (xmlNodePtr)node->properties;
	
	while (attributes)
	{
		if (attributes->name && (strcmp((char*)attributes->name, attr_name)==0))
		{
			return attributes;
		}
		attributes = attributes->next;
	}
	return NULL;
}

xmlXPathObjectPtr quick_query( xmlXPathContextPtr ctx, xmlNodePtr ctx_node, const char* query_format, ... )
{
	va_list list;
	va_start(list,query_format);
	
	xmlNodePtr tmp = ctx->node;
	ctx->node = ctx_node;
	char query[8192];
	vsnprintf(query,8192,query_format,list);
	xmlXPathObjectPtr nodes = xmlXPathEval((xmlChar*)query, ctx);
	va_end(list);
	ctx->node = tmp;
	return  nodes;
}

xmlNodePtr quick_query_node( xmlXPathContextPtr ctx, xmlNodePtr ctx_node, const char* query_format, ... )
{
	va_list list;
	va_start(list,query_format);
	
	xmlNodePtr tmp = ctx->node;
	ctx->node = ctx_node;
	char query[LOCAL_BUF_SIZE];
	
	vsnprintf(query,LOCAL_BUF_SIZE,query_format,list);
	xmlXPathObjectPtr nodes = xmlXPathEval((xmlChar*)query, ctx);
	va_end(list);
	ctx->node = tmp;
	tmp = NULL;
	if(xmlXPathCastToBoolean(nodes))
	{
		if(nodes->nodesetval->nodeNr==1)
			tmp = nodes->nodesetval->nodeTab[0];
		else
			tmp = NULL;
	}
	if(nodes)
		xmlXPathFreeObject(nodes);
	return tmp;
}

void quick_prop( xmlNodePtr node, const char* name, const char* format, ... )
{
	char prop[LOCAL_BUF_SIZE];
	va_list list;
	va_start(list,format);
	vsnprintf(prop,LOCAL_BUF_SIZE,format,list);
	va_end(list);
	
	xmlNodePtr tmp = get_attribute_node(node,name);
	if(tmp)
		xmlNodeSetContent(tmp,(xmlChar*)prop);
	else
		xmlNewProp(node,(xmlChar*)name,(xmlChar*)prop);
}

void address_init( struct sockaddr_in* addr, const char* address, uint16_t port )
{
	memset(addr,0,sizeof(struct sockaddr_in));
	char* p = strstr(address,":");
	if(p)
	{
		*p='\0';
		p++;
		port=atoi(p);
	}
	
	struct hostent* h = gethostbyname(address);
	if(h)
	{
		struct in_addr **addr_list = (struct in_addr **)h->h_addr_list;
		addr->sin_addr.s_addr = addr_list[0]->s_addr;
		addr->sin_family = AF_INET;
		addr->sin_port = htons(port);
	}
	else
	{
		addr->sin_addr.s_addr = inet_addr(address);
		addr->sin_family = AF_INET;
		addr->sin_port = htons(port);
	}
}


void remove_extra_line_feeds(xmlDocPtr doc)
{
	xmlXPathContextPtr c = xmlXPathNewContext(doc);
	xmlXPathObjectPtr ws = xmlXPathEval((xmlChar*)"//text()",c);
	if(xmlXPathCastToBoolean(ws))
	{
		int i;
		for(i=0;i<ws->nodesetval->nodeNr;i++)
		{
			xmlNodePtr n = ws->nodesetval->nodeTab[i];
			char* v = get_node_content(n);
			if(v && strcmp(v,"\n")==0)
			{
				xmlUnlinkNode(n);
				xmlFreeNode(n);
			}
		}
	}
	if(ws)
		xmlXPathFreeObject(ws);
	xmlXPathFreeContext(c);
}

static int __mkdir(char* path)
{
	int cd = open(path,O_RDONLY);
	if(cd < 0)
		mkdir(path,(S_IRWXU | S_IRWXG | S_IRWXO));
	else
	{
		struct stat stat;
		fstat(cd,&stat);
		if((stat.st_mode & S_IFDIR) == 0)
		{
			close(cd);
			return -1;
		}
		close(cd);
	}
	return 0;
}

int mkdir_p(char* path)
{
	char* tmp = malloc(strlen(path)+1);
	
	char* p = strstr(path,"/");
	if(!p)
		return __mkdir(path);
	for(p=strstr(path,"/");p;p=strstr(p+1,"/"))
	{
		if(p==path)
			continue;
		
		memcpy(tmp,path,p-path);
		tmp[p-path]=0;
		if(__mkdir(tmp))
		{
			free(tmp);
			return -1;
		}
	}
	free(tmp);
	return 0;
}

int get_attribute_value_as_int(xmlNodePtr node, const char* name)
{
	char* strvalue = (char*)get_attribute_value(node,name);
	if(!strvalue)
		return -1;
	
	int32_t id = strtold(strvalue,NULL);
	return id;
}

int32_t get_id_attribute(xmlNodePtr node)
{
	return get_attribute_value_as_int(node,"id");
}

void set_id_attribute(xmlNodePtr node, int32_t id)
{
	quick_prop(node,"id","%d",id);
}

char* get_node_content(xmlNodePtr node)
{
	while(node && node->type != XML_TEXT_NODE)
		node=node->children;
	
	if(node)
		return (char*)XML_GET_CONTENT(node);
	
	return NULL;
}

#endif